﻿using Duende.IdentityServer.Configuration;
using Duende.IdentityServer.Services;
using Duende.IdentityServer;
using Service.Auth.Api.Application.Query;
using Service.Auth.Domain.AggregatesModel;
using Service.Core.Redis.Services;
using Service.Framework.Utils;
using Duende.IdentityServer.Models;
using IdentityModel;

namespace Service.Auth.Api.Application.IdsValidator
{
    /// <summary>
    /// 自定义token生成器
    /// </summary>
    public class CustomTokenCreationService : DefaultTokenCreationService
    {
        private readonly UserQueryService _userQueryService;

        private readonly IRedisService _redisService;
        /// <summary>
        /// 
        /// </summary>
        /// <param name="clock"></param>
        /// <param name="keys"></param>
        /// <param name="options"></param>
        /// <param name="logger"></param>
        public CustomTokenCreationService(IClock clock, IKeyMaterialService keys, IdentityServerOptions options, ILogger<DefaultTokenCreationService> logger, UserQueryService userQueryService, IRedisService redisService) : base(clock, keys, options, logger)
        {
            _userQueryService = userQueryService;
            _redisService = redisService;
        }

        /// <summary>
        /// 创建令牌,所有的令牌都将通过此方法生成
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        public override async Task<string> CreateTokenAsync(Token token)
        {
            //还需要给每个用户添加一个最新的JTI
            var result = await base.CreateTokenAsync(token);
            // 如果是access_token，则将用户信息存入Redis
            if (token.Type == "access_token" && !string.IsNullOrEmpty(token.SubjectId))
            {
                var jwtId = token.Claims
                    .FirstOrDefault(c => c.Type == JwtClaimTypes.JwtId)?.Value;
                var loginUserInfo = await _userQueryService.BuildLoginUserInfo(long.Parse(token.SubjectId));
                await _redisService.Database.StringSetAsync($"{nameof(User)}:{token.SubjectId}", JsonSerializeUtil.SerializeObject(loginUserInfo), TimeSpan.FromSeconds(token.Lifetime));
                await _redisService.Database.StringSetAsync($"{nameof(User)}:{token.SubjectId}:latestJti", jwtId, TimeSpan.FromSeconds(token.Lifetime));
            }

            return result;

        }
    }
}
